/*
 * HttpHost.h
 *
 */

#ifndef HTTPHOST_H_
#define HTTPHOST_H_

#include "../Process.h"

class HttpBody;
class HttpRequest;
class HttpResponse;
class HttpGet;
class HttpPost;
class LogFile;
class ServerConfig;

class HostException : public std::exception {
	private:
		std::string msg;
	public:
		explicit HostException(const std::string& msg) throw();
		virtual ~HostException() throw() {}
		const char* what() const throw() { return msg.c_str(); }
};

class HttpHost {
	private:
		static const int DATA_BUFFER_SIZE = 512;
		const ServerConfig& config;
		LogFile& logFile;
		const std::string id;
		Process process;

	protected:
		/** Intenta procesar un request estáticamente y loguea el resultado.
		 * @param response Instancia donde carga el resultado si procesa el request.
		 * @param request Instancia de donde toma los datos a procesar.
		 * @param resource Cadena con el nombre del recurso parseado.
		 * @param params Cadena con los parámetros que pueden seguir al resource.
		 * @return Verdadero si lo pudó procesar.
		 */
		bool staticProcess(HttpResponse& response, const HttpRequest& request,
				const std::string& resource, const std::string& params);

		/** Intenta procesar un request dinámicamente y loguea el resultado.
		 * @param response Instancia donde carga el resultado si procesa el request.
		 * @param request Instancia de donde toma los datos a procesar.
		 * @param resource Cadena con el nombre del recurso parseado.
		 * @param params Cadena con los parámetros que pueden seguir al resource.
		 * @return Verdadero si lo pudó procesar.
		 */
		bool dynamicProcess(HttpResponse& response, const HttpRequest& request,
				const std::string& resource, const std::string& params);

		/** Si el server requiere validación, analiza que el cliente lo esté.
		 * Solo soporta autenticación BASIC.
		 * @param response Instancia donde carga un mensaje al cliente si no
		 * está autenticado y así se requiere.
		 * @param request Instancia de donde toma los datos del usuario.
		 * @return Verdadero si no se requiere autenticación o si ya lo está.
		 */
		bool authenticated(HttpResponse& response, const HttpRequest& request);

		/** Procesa la salida de un script CGI y loguea el resultado.
		 * @param response Instancia donde carga el resultado si procesa la data.
		 * @param request Instancia de donde toma los datos del cliente.
		 * @param data Stream con la salida del script a analizar.
		 * @param scriptName Cadena con el nombre del script ejecutado.
		 */
		void cgiOutputProcess(HttpResponse& response, const HttpRequest& request,
				std::stringstream& data, const std::string& scriptName);

		/** Devuelve la ruta física del uri solicitado.
		 * @param resource Uri solicitado por el cliente.
		 * @return Cadena con el path al uri.
		 */
		std::string resourcePath(const std::string& resource) const;

		/** Devuelve la extensión de el uri pasado.
		 * @param resource Uri del cual obtener la conexión del cliente.
		 * @return Cadena con la extensión extraida.
		 */
		std::string resourceExtension(const std::string& resource) const;
	public:
		/** Crea una instancia asociada al cliente id.
		 * @param config Referencia a la configuración del servidor.
		 * @param logFile Referencia a la clase que maneja el logueo del server
		 * @param id Id del cliente.
		 */
		HttpHost(const ServerConfig& config, LogFile& logFile,
				const std::string& id);

		virtual ~HttpHost();

		/** Carga la página del código de error correspondiente.
		 * @param response HttpResponse donde cargará la página de error solcicitada.
		 * @param code Código de error solicitado.
		 */
		void errorProcess(HttpResponse& response, int code);

		/** Crea una respuesta a la solicitud requerida.
		 * @param response HttpResponse donde cargará la respuesta generada.
		 * @param request Solicitud de la cual tomará los datos a procesar.
		 */
		void generateResponse(HttpResponse& response,
				const HttpRequest& message);

		/**
		 * Fuerza la finalizacíon de la instancia.
		 */
		void terminate();

		static const std::string PROTOCOL_NAME;
		static const std::string MAYOR_VERSION;
		static const std::string MINOR_VERSION;
		static const std::string HTTP_VERSION;
};

#endif /* HTTPHOST_H_ */
